/**
 * 前端代码生成器
 * 使用 Handlebars.js 直接渲染 .hbs 模板文件
 */

import Handlebars from 'handlebars'
import JSZip from 'jszip'
import { saveAs } from 'file-saver'
import type { DatabaseTableVO, DatabaseFieldVO } from '@@/apis/database/type'

// 导入所有模板文件
import controllerTemplate from '../templates/spring-boot/controller.hbs?raw'
import serviceTemplate from '../templates/spring-boot/service.hbs?raw'
import serviceImplTemplate from '../templates/spring-boot/service-impl.hbs?raw'
import entityTemplate from '../templates/spring-boot/entity.hbs?raw'
import dtoTemplate from '../templates/spring-boot/dto.hbs?raw'
import voTemplate from '../templates/spring-boot/vo.hbs?raw'
import mapperTemplate from '../templates/spring-boot/mapper.hbs?raw'
import mapperXmlTemplate from '../templates/spring-boot/mapper.xml.hbs?raw'
import resultTemplate from '../templates/spring-boot/result.hbs?raw'
import pageResultTemplate from '../templates/spring-boot/page-result.hbs?raw'
import errorCodeTemplate from '../templates/spring-boot/error-code.hbs?raw'
import knife4jConfigTemplate from '../templates/spring-boot/knife4j-config.hbs?raw'
import pomXmlTemplate from '../templates/spring-boot/pom.xml.hbs?raw'
import applicationYmlTemplate from '../templates/spring-boot/application.yml.hbs?raw'

/** 项目生成配置 */
export interface ProjectConfig {
  projectName: string
  packageName: string
  author: string
  version: string
  description?: string
  frameworkType: string
  
  // 数据库配置
  database: {
    type: string
    host: string
    port: number
    database: string
    username: string
    password: string
  }
  
  // Redis配置（可选）
  redis?: {
    host: string
    port: number
    password?: string
    database: number
    timeout: number
  }
  
  // JWT配置（可选）
  jwt?: {
    secret: string
    expiration: number // 小时
    refreshExpiration: number // 天
  }
  
  // 功能开关
  features: {
    enableSecurity: boolean
    enableCache: boolean
    enableActuator: boolean
    enableDocker: boolean
    enableMonitoring: boolean
  }
}

/** 前端代码生成器 */
export class FrontendCodeGenerator {
  private handlebars: typeof Handlebars
  private templates: Map<string, HandlebarsTemplateDelegate>

  constructor() {
    this.handlebars = Handlebars.create()
    this.templates = new Map()
    this.registerHelpers()
    this.compileTemplates()
  }

  /**
   * 注册 Handlebars 辅助函数
   */
  private registerHelpers(): void {
    // 转换为驼峰命名
    this.handlebars.registerHelper('camelCase', (str: string) => {
      if (!str) return ''
      return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
        .replace(/^[A-Z]/, letter => letter.toLowerCase())
    })

    // 转换为帕斯卡命名
    this.handlebars.registerHelper('pascalCase', (str: string) => {
      if (!str) return ''
      return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase())
        .replace(/^[a-z]/, letter => letter.toUpperCase())
    })

    // 转换为小写
    this.handlebars.registerHelper('lowerCase', (str: any) => {
      return str && typeof str === 'string' ? str.toLowerCase() : ''
    })

    // 转换为大写
    this.handlebars.registerHelper('upperCase', (str: any) => {
      return str && typeof str === 'string' ? str.toUpperCase() : ''
    })

    // 转换为下划线命名
    this.handlebars.registerHelper('snakeCase', (str: any) => {
      if (!str || typeof str !== 'string') return ''
      return str.replace(/([A-Z])/g, '_$1').toLowerCase().replace(/^_/, '')
    })

    // 条件判断
    this.handlebars.registerHelper('eq', (a: any, b: any) => a === b)
    this.handlebars.registerHelper('ne', (a: any, b: any) => a !== b)
    this.handlebars.registerHelper('gt', (a: any, b: any) => a > b)
    this.handlebars.registerHelper('lt', (a: any, b: any) => a < b)
    this.handlebars.registerHelper('and', (a: any, b: any) => a && b)
    this.handlebars.registerHelper('or', (a: any, b: any) => a || b)
    
    // 字符串处理
    this.handlebars.registerHelper('upperFirst', (str: any) => {
      if (!str || typeof str !== 'string') return ''
      return str.charAt(0).toUpperCase() + str.slice(1)
    })
    this.handlebars.registerHelper('not', (a: any) => !a)

    // 数组操作
    this.handlebars.registerHelper('length', (arr: any[]) => arr ? arr.length : 0)
    this.handlebars.registerHelper('first', (arr: any[]) => arr && arr.length > 0 ? arr[0] : null)
    this.handlebars.registerHelper('last', (arr: any[]) => arr && arr.length > 0 ? arr[arr.length - 1] : null)

    // 字符串操作
    this.handlebars.registerHelper('replace', (str: string, search: string, replace: string) => {
      return str ? str.replace(new RegExp(search, 'g'), replace) : ''
    })

    // 日期格式化
    this.handlebars.registerHelper('formatDate', (date?: Date) => {
      const d = date || new Date()
      return d.toISOString().split('T')[0]
    })

    // Java类型映射
    this.handlebars.registerHelper('javaType', (dbType: string) => {
      const typeMap: Record<string, string> = {
        'varchar': 'String',
        'char': 'String',
        'text': 'String',
        'longtext': 'String',
        'int': 'Integer',
        'bigint': 'Long',
        'tinyint': 'Boolean',
        'decimal': 'BigDecimal',
        'double': 'Double',
        'float': 'Float',
        'datetime': 'LocalDateTime',
        'timestamp': 'LocalDateTime',
        'date': 'LocalDate',
        'time': 'LocalTime'
      }
      const safeDbType = dbType && typeof dbType === 'string' ? dbType.toLowerCase() : 'varchar'
      return typeMap[safeDbType] || 'String'
    })

    // MyBatis类型映射
    this.handlebars.registerHelper('mybatisType', (dbType: string) => {
      const typeMap: Record<string, string> = {
        'varchar': 'VARCHAR',
        'char': 'CHAR',
        'text': 'LONGVARCHAR',
        'longtext': 'LONGVARCHAR',
        'int': 'INTEGER',
        'bigint': 'BIGINT',
        'tinyint': 'TINYINT',
        'decimal': 'DECIMAL',
        'double': 'DOUBLE',
        'float': 'FLOAT',
        'datetime': 'TIMESTAMP',
        'timestamp': 'TIMESTAMP',
        'date': 'DATE',
        'time': 'TIME'
      }
      const safeDbType = dbType && typeof dbType === 'string' ? dbType.toLowerCase() : 'varchar'
      return typeMap[safeDbType] || 'VARCHAR'
    })
  }

  /**
   * 编译所有模板
   */
  private compileTemplates(): void {
    const templateMap = {
      'controller.hbs': controllerTemplate,
      'service.hbs': serviceTemplate,
      'service-impl.hbs': serviceImplTemplate,
      'entity.hbs': entityTemplate,
      'dto.hbs': dtoTemplate,
      'vo.hbs': voTemplate,
      'mapper.hbs': mapperTemplate,
      'mapper.xml.hbs': mapperXmlTemplate,
      'result.hbs': resultTemplate,
      'page-result.hbs': pageResultTemplate,
      'error-code.hbs': errorCodeTemplate,
      'knife4j-config.hbs': knife4jConfigTemplate,
      'pom.xml.hbs': pomXmlTemplate,
      'application.yml.hbs': applicationYmlTemplate
    }

    for (const [name, content] of Object.entries(templateMap)) {
      try {
        const compiled = this.handlebars.compile(content)
        this.templates.set(name, compiled)
      } catch (error) {
        console.error(`编译模板失败: ${name}`, error)
      }
    }
  }

  /**
   * 生成完整项目
   */
  async generateProject(config: ProjectConfig, tables: DatabaseTableVO[]): Promise<void> {
    const zip = new JSZip()
    
    // 生成项目基础数据
    const projectData = this.generateProjectData(config)
    
    // 生成项目级别文件
    this.generateProjectFiles(zip, projectData)
    
    // 为每个表生成代码
    for (const table of tables) {
      const fields = table.fields || []
      const tableData = this.generateTableData(table, fields, config)
      this.generateTableFiles(zip, tableData, config)
    }
    
    // 下载ZIP文件
    const content = await zip.generateAsync({ type: 'blob' })
    saveAs(content, `${config.projectName}.zip`)
  }

  /**
   * 生成项目基础数据
   */
  private generateProjectData(config: ProjectConfig): Record<string, any> {
    const packagePath = config.packageName.replace(/\./g, '/')
    const groupId = config.packageName.split('.').slice(0, -1).join('.')
    const artifactId = config.projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-')

    return {
      // 基本信息
      projectName: config.projectName,
      packageName: config.packageName,
      basePackage: config.packageName, // 模板中使用的变量名
      packagePath,
      groupId,
      artifactId,
      author: config.author,
      version: config.version,
      description: config.description || config.projectName,
      createTime: new Date().toISOString().split('T')[0],
      
      // 数据库配置
      database: config.database,
      
      // Redis配置
      redis: config.redis,
      
      // JWT配置
      jwt: config.jwt,
      
      // 功能开关 - 完全基于用户配置
      enableSecurity: config.features.enableSecurity,
      enableCache: config.features.enableCache,
      enableActuator: config.features.enableActuator || true, // Spring Boot Actuator默认启用
      enableRedis: config.features.enableCache, // Redis与缓存功能绑定
      enableJwt: config.features.enableSecurity, // JWT与安全功能绑定
      enableDocker: config.features.enableDocker, // 用户选择的容器化配置
      enableMonitoring: config.features.enableMonitoring, // 用户选择的监控配置
      
      // 技术栈选择 - 基于用户配置但提供合理默认值
      enableDruid: config.features.enableCache || true, // 如果启用缓存或默认启用连接池
      enablePageHelper: true, // 分页插件通常都需要
      enableGenerator: false, // 运行时不需要代码生成器
      enableAliyunRepo: true, // 国内用户友好的仓库配置
      
      // 技术配置
      springBootVersion: '2.7.18',
      knife4jVersion: '4.4.0',
      mybatisPlusVersion: '3.5.3',
      javaVersion: '8',
      mysqlVersion: '8.0.33',
      commonsIoVersion: '2.11.0',
      druidVersion: '1.2.20',
      pageHelperVersion: '1.4.7',
      jwtVersion: '0.11.5',
      
      // 日志配置
      logLevel: 'INFO',
      sqlLogLevel: 'DEBUG'
    }
  }

  /**
   * 生成表数据
   */
  private generateTableData(table: DatabaseTableVO, fields: DatabaseFieldVO[], config: ProjectConfig): Record<string, any> {
    const entityName = this.toPascalCase(table.tableName)
    const packagePath = config.packageName.replace(/\./g, '/')

    return {
      // 表信息
      tableName: table.tableName,
      tableComment: table.tableComment || table.tableName,
      entityName,
      entityNameLower: entityName.toLowerCase(),
      
      // 包信息
      packageName: config.packageName,
      basePackage: config.packageName, // 模板中使用的变量名
      packagePath,
      
      // 字段信息
      fields: fields.map(field => ({
        ...field,
        fieldName: this.toCamelCase(field.fieldName),
        fieldNamePascal: this.toPascalCase(field.fieldName),
        columnName: field.fieldName, // 原始数据库字段名
        comment: field.fieldComment || field.fieldName, // 模板中使用的注释字段
        fieldComment: field.fieldComment || field.fieldName,
        javaType: this.getJavaType(field.fieldType),
        mybatisType: this.getMybatisType(field.fieldType),
        isPrimaryKey: field.isPrimaryKey,
        isRequired: !field.isNullable, // 非空即为必填
        idType: field.isPrimaryKey ? 'AUTO' : undefined, // 主键类型
        isLogicDelete: field.fieldName === 'deleted' || field.fieldName === 'is_deleted' // 逻辑删除字段
      })),
      
      // 主键字段
      primaryKey: fields.find(f => f.isPrimaryKey),
      
      // 查询字段 (非主键字段用于查询条件)
      queryFields: fields.filter(f => !f.isPrimaryKey && f.fieldName && f.fieldName.trim().length > 0).map(field => ({
        ...field,
        fieldName: this.toCamelCase(field.fieldName || 'defaultField'),
        javaType: this.getJavaType(field.fieldType || 'VARCHAR'),
        queryType: this.getQueryType(field.fieldType || 'VARCHAR'), // 根据字段类型确定查询方式
        comment: field.fieldComment || field.fieldName || 'Unknown Field'
      })),
      
      // 必填字段 (非空且非主键字段)
      requiredFields: fields.filter(f => !f.isPrimaryKey && !f.isNullable && f.fieldName && f.fieldName.trim().length > 0).map(field => ({
        ...field,
        fieldName: this.toCamelCase(field.fieldName || 'defaultField'),
        javaType: this.getJavaType(field.fieldType || 'VARCHAR'),
        comment: field.fieldComment || field.fieldName || 'Unknown Field'
      })),
      
      // 关联关系 - 暂时禁用以确保基本功能正常
      hasRelations: false,
      relations: [],
      
      // 项目信息
      author: config.author,
      version: config.version,
      createTime: new Date().toISOString().split('T')[0]
    }
  }

  /**
   * 生成项目级别文件
   */
  private generateProjectFiles(zip: JSZip, data: Record<string, any>): void {
    const packagePath = data.packagePath

    // pom.xml
    const pomContent = this.renderTemplate('pom.xml.hbs', data)
    if (pomContent) {
      zip.file('pom.xml', pomContent)
    }

    // application.yml
    const appYmlContent = this.renderTemplate('application.yml.hbs', data)
    if (appYmlContent) {
      zip.file('src/main/resources/application.yml', appYmlContent)
    }

    // 通用类文件
    const resultContent = this.renderTemplate('result.hbs', data)
    if (resultContent) {
      zip.file(`src/main/java/${packagePath}/common/Result.java`, resultContent)
    }

    const pageResultContent = this.renderTemplate('page-result.hbs', data)
    if (pageResultContent) {
      zip.file(`src/main/java/${packagePath}/common/PageResult.java`, pageResultContent)
    }

    const errorCodeContent = this.renderTemplate('error-code.hbs', data)
    if (errorCodeContent) {
      zip.file(`src/main/java/${packagePath}/common/ErrorCode.java`, errorCodeContent)
    }

    // Knife4j配置
    const knife4jContent = this.renderTemplate('knife4j-config.hbs', data)
    if (knife4jContent) {
      zip.file(`src/main/java/${packagePath}/config/Knife4jConfig.java`, knife4jContent)
    }
  }

  /**
   * 生成表相关文件
   */
  private generateTableFiles(zip: JSZip, data: Record<string, any>, config: ProjectConfig): void {
    const packagePath = data.packagePath
    const entityName = data.entityName

    // Entity
    const entityContent = this.renderTemplate('entity.hbs', data)
    if (entityContent) {
      zip.file(`src/main/java/${packagePath}/entity/${entityName}.java`, entityContent)
    }

    // DTO
    const dtoContent = this.renderTemplate('dto.hbs', data)
    if (dtoContent) {
      zip.file(`src/main/java/${packagePath}/dto/${entityName}DTO.java`, dtoContent)
    }

    // VO
    const voContent = this.renderTemplate('vo.hbs', data)
    if (voContent) {
      zip.file(`src/main/java/${packagePath}/vo/${entityName}VO.java`, voContent)
    }

    // Mapper接口
    const mapperContent = this.renderTemplate('mapper.hbs', data)
    if (mapperContent) {
      zip.file(`src/main/java/${packagePath}/mapper/${entityName}Mapper.java`, mapperContent)
    }

    // Mapper XML
    const mapperXmlContent = this.renderTemplate('mapper.xml.hbs', data)
    if (mapperXmlContent) {
      zip.file(`src/main/resources/mapper/${entityName}Mapper.xml`, mapperXmlContent)
    }

    // Service接口
    const serviceContent = this.renderTemplate('service.hbs', data)
    if (serviceContent) {
      zip.file(`src/main/java/${packagePath}/service/${entityName}Service.java`, serviceContent)
    }

    // Service实现
    const serviceImplContent = this.renderTemplate('service-impl.hbs', data)
    if (serviceImplContent) {
      zip.file(`src/main/java/${packagePath}/service/impl/${entityName}ServiceImpl.java`, serviceImplContent)
    }

    // Controller
    const controllerContent = this.renderTemplate('controller.hbs', data)
    if (controllerContent) {
      zip.file(`src/main/java/${packagePath}/controller/${entityName}Controller.java`, controllerContent)
    }
  }

  /**
   * 渲染模板
   */
  private renderTemplate(templateName: string, data: Record<string, any>): string | null {
    const template = this.templates.get(templateName)
    if (!template) {
      console.warn(`模板不存在: ${templateName}`)
      return null
    }

    try {
      return template(data)
    } catch (error) {
      console.error(`渲染模板失败: ${templateName}`, error)
      return null
    }
  }

  /**
   * 工具方法：转换为驼峰命名
   */
  private toCamelCase(str: string): string {
    if (!str || str.trim().length === 0) return 'defaultField'
    
    // 处理下划线分隔的命名
    const parts = str.trim().split('_')
    if (parts.length === 1) {
      return parts[0].toLowerCase()
    }
    
    return parts[0].toLowerCase() + 
           parts.slice(1).map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join('')
  }

  /**
   * 工具方法：转换为帕斯卡命名
   */
  private toPascalCase(str: string): string {
    if (!str || str.trim().length === 0) return 'DefaultEntity'
    
    // 处理下划线分隔的命名
    return str.trim()
      .split('_')
      .map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
      .join('')
  }

  /**
   * 获取Java类型
   */
  private getJavaType(dbType: string): string {
    const typeMap: Record<string, string> = {
      'varchar': 'String',
      'char': 'String',
      'text': 'String',
      'longtext': 'String',
      'int': 'Integer',
      'bigint': 'Long',
      'tinyint': 'Boolean',
      'decimal': 'BigDecimal',
      'double': 'Double',
      'float': 'Float',
      'datetime': 'LocalDateTime',
      'timestamp': 'LocalDateTime',
      'date': 'LocalDate',
      'time': 'LocalTime'
    }
    const safeDbType = dbType && typeof dbType === 'string' ? dbType.toLowerCase() : 'varchar'
    return typeMap[safeDbType] || 'String'
  }

  /**
   * 智能分析表关联关系
   */
  private analyzeTableRelations(table: DatabaseTableVO, fields: DatabaseFieldVO[]): Array<{
    relatedEntity: string
    relatedTable: string
    foreignKey: string
    comment: string
    relationType: 'oneToMany' | 'manyToOne' | 'oneToOne'
  }> {
    const relations: Array<{
      relatedEntity: string
      relatedTable: string
      foreignKey: string
      comment: string
      relationType: 'oneToMany' | 'manyToOne' | 'oneToOne'
    }> = []

    // 分析外键字段 (以 _id 结尾且不是主键的字段)
    fields.forEach(field => {
      if (field.fieldName.endsWith('_id') && !field.isPrimaryKey) {
        // 推断关联表名
        const relatedTableName = field.fieldName.replace('_id', '')
        
        // 安全检查：确保关联表名不为空
        if (relatedTableName && relatedTableName.length > 0) {
          const relatedEntity = this.toPascalCase(relatedTableName)
          
          // 安全检查：确保实体名不为空
          if (relatedEntity && relatedEntity.length > 0) {
            relations.push({
              relatedEntity,
              relatedTable: relatedTableName,
              foreignKey: field.fieldName,
              comment: field.fieldComment || `关联的${relatedEntity}`,
              relationType: 'manyToOne'
            })
          }
        }
      }
    })

    // 分析反向关联 (其他表可能引用当前表的主键)
    const primaryKey = fields.find(f => f.isPrimaryKey)
    if (primaryKey) {
      // 这里可以根据命名约定推断可能的子表
      // 例如：order_main -> order_item (通过 order_id 关联)
      const tableName = table.tableName
      const possibleChildTables = this.inferChildTables(tableName)
      
      possibleChildTables.forEach(childTable => {
        // 安全检查：确保子表名不为空
        if (childTable && childTable.length > 0) {
          const relatedEntity = this.toPascalCase(childTable)
          
          // 安全检查：确保实体名不为空
          if (relatedEntity && relatedEntity.length > 0) {
            relations.push({
              relatedEntity,
              relatedTable: childTable,
              foreignKey: `${tableName}_id`,
              comment: `${table.tableComment || tableName}的${relatedEntity}列表`,
              relationType: 'oneToMany'
            })
          }
        }
      })
    }

    return relations
  }

  /**
   * 根据表名推断可能的子表
   */
  private inferChildTables(tableName: string): string[] {
    const childTables: string[] = []
    
    // 常见的主子表命名模式
    const patterns = [
      { main: 'order_main', child: 'order_item' },
      { main: 'user', child: 'user_address' },
      { main: 'product', child: 'product_comment' },
      { main: 'category', child: 'product' }
    ]
    
    patterns.forEach(pattern => {
      if (tableName === pattern.main) {
        childTables.push(pattern.child)
      }
    })
    
    // 通用模式：如果表名以 _main 结尾，推断对应的 _item 表
    if (tableName.endsWith('_main')) {
      const baseName = tableName.replace('_main', '')
      childTables.push(`${baseName}_item`)
    }
    
    return childTables
  }

  /**
   * 获取查询类型
   */
  private getQueryType(dbType: string): string {
    const lowerType = dbType.toLowerCase()
    
    // 字符串类型使用模糊查询
    if (lowerType.includes('varchar') || lowerType.includes('text') || lowerType.includes('char')) {
      return 'like'
    }
    
    // 日期时间类型使用范围查询
    if (lowerType.includes('date') || lowerType.includes('time')) {
      return 'range'
    }
    
    // 数值类型使用精确查询
    return 'eq'
  }

  /**
   * 获取MyBatis类型
   */
  private getMybatisType(dbType: string): string {
    const typeMap: Record<string, string> = {
      'varchar': 'VARCHAR',
      'char': 'CHAR',
      'text': 'LONGVARCHAR',
      'longtext': 'LONGVARCHAR',
      'int': 'INTEGER',
      'bigint': 'BIGINT',
      'tinyint': 'TINYINT',
      'decimal': 'DECIMAL',
      'double': 'DOUBLE',
      'float': 'FLOAT',
      'datetime': 'TIMESTAMP',
      'timestamp': 'TIMESTAMP',
      'date': 'DATE',
      'time': 'TIME'
    }
    const safeDbType = dbType && typeof dbType === 'string' ? dbType.toLowerCase() : 'varchar'
    return typeMap[safeDbType] || 'VARCHAR'
  }
}
